﻿using System;
using JTLeigh.Commerce.Spencer.Core.Common.Exceptions;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace JTLeigh.Commerce.Spencer.Core.Common.UnitTests
{

	/// <summary>
	/// Unit tests for the <see cref="Safety"/> class.
	/// </summary>
	[TestClass]
	public class SafetyFixture
	{

		#region Methods

		#region AssertArgumentNotNull

		/// <summary>
		/// Ensures <see cref="Safety.AssertArgumentNotNull"/> does not throw an an exception when
		/// called with a non-<see langword="null"/> argument value.
		/// </summary>
		[TestMethod]
		public void TestAssertArgumentNotNullWithNonNullArgumentValue()
		{
			Safety.AssertArgumentNotNull("argumentName", "argumentValue");
		}

		/// <summary>
		/// Ensures <see cref="Safety.AssertArgumentNotNull"/> correctly throws <see cref="ArgumentNullException"/>
		/// when called with a <see langword="null"/> argument name.
		/// </summary>
		[TestMethod]
		[ExpectedException(typeof(ArgumentNullException))]
		public void TestAssertArgumentNotNullWithNullArgumentName()
		{
			Safety.AssertArgumentNotNull(null, "argumentValue");
		}

		/// <summary>
		/// Ensures <see cref="Safety.AssertArgumentNotNull"/> correctly throws <see cref="AssertionFailedException"/>
		/// when called with a <see langword="null"/> argument value.
		/// </summary>
		[TestMethod]
		[ExpectedException(typeof(AssertionFailedException))]
		public void TestAssertArgumentNotNullWithNullArgumentValue()
		{
			Safety.AssertArgumentNotNull("argumentName", null);
		}

		#endregion // AssertArgumentNotNull

		#region AssertNotNull

		/// <summary>
		/// Ensures <see cref="Safety.AssertNotNull"/> does not throw an exception when called with
		/// a non-<see langword="null"/> value.
		/// </summary>
		[TestMethod]
		public void TestAssertNotNullWithNonNullValue()
		{
			Safety.AssertNotNull("value", "message");
		}

		/// <summary>
		/// Ensures <see cref="Safety.AssertNotNull"/> correctly throws <see cref="AssertionFailedException"/>
		/// when called with a <see langword="null"/> value.
		/// </summary>
		[TestMethod]
		[ExpectedException(typeof(AssertionFailedException))]
		public void TestAssertNotNullWithNullValue()
		{
			Safety.AssertNotNull(null, "message");
		}

		/// <summary>
		/// Ensures <see cref="Safety.AssertNotNull"/> correctly throws <see cref="ArgumentNullException"/>
		/// when called with a <see langword="null"/> message.
		/// </summary>
		[TestMethod]
		[ExpectedException(typeof(ArgumentNullException))]
		public void TestAssertNotNullWithNullMessage()
		{
			Safety.AssertNotNull("value", null);
		}

		#endregion // AssertNotNull

		#region AssertTrue

		/// <summary>
		/// Ensures <see cref="Safety.AssertTrue"/> does not throw an exception when called with a
		/// <see langword="true"/> value.
		/// </summary>
		[TestMethod]
		public void TestAssertTrueWithTrueValue()
		{
			Safety.AssertTrue(true, "message");
		}

		/// <summary>
		/// Ensures <see cref="Safety.AssertTrue"/> throws <see cref="AssertionFailedException"/> 
		/// when called with a <see langword="false"/> value.
		/// </summary>
		[TestMethod]
		[ExpectedException(typeof(AssertionFailedException))]
		public void TestAssertTrueWithFalseValue()
		{
			Safety.AssertTrue(false, "message");
		}

		/// <summary>
		/// Ensures <see cref="Safety.AssertTrue"/> correctly throws <see cref="ArgumentNullException"/>
		/// when called with a <see langword="null"/> message.
		/// </summary>
		[TestMethod]
		[ExpectedException(typeof(ArgumentNullException))]
		public void TestAssertTrueWithNullMessage()
		{
			Safety.AssertTrue(true, null);
		}

		#endregion // AssertTrue

		#region AssertFalse

		/// <summary>
		/// Ensures <see cref="Safety.AssertFalse"/> does not throw an exception when called with a
		/// <see langword="false"/> value.
		/// </summary>
		[TestMethod]
		public void TestAssertFalseWithFalseValue()
		{
			Safety.AssertFalse(false, "message");
		}

		/// <summary>
		/// Ensures <see cref="Safety.AssertFalse"/> correctly throws <see cref="AssertionFailedException"/> 
		/// when called with a <see langword="true"/> value.
		/// </summary>
		[TestMethod]
		[ExpectedException(typeof(AssertionFailedException))]
		public void TestAssertFalseWithTrueValue()
		{
			Safety.AssertFalse(true, "message");
		}

		/// <summary>
		/// Ensures <see cref="Safety.AssertFalse"/> correctly throws <see cref="ArgumentNullException"/>
		/// when called with a <see langword="null"/> message.
		/// </summary>
		[TestMethod]
		[ExpectedException(typeof(ArgumentNullException))]
		public void TestAssertFalseWithNullMessage()
		{
			Safety.AssertFalse(false, null);
		}

		#endregion // AssertFalse

		#region AssertEqual

		/// <summary>
		/// Ensures <see cref="Safety.AssertEqual"/> does not throw an exception when called with
		/// the expected value.
		/// </summary>
		[TestMethod]
		public void TestAssertEqualWithExpectedValue()
		{
			Safety.AssertEqual("value", "value", "message");
		}

		/// <summary>
		/// Ensures <see cref="Safety.AssertEqual"/> throws <see cref="AssertionFailedException"/> 
		/// when called with an unexpected value.
		/// </summary>
		[TestMethod]
		[ExpectedException(typeof(AssertionFailedException))]
		public void TestAssertEqualWithUnexpectedValue()
		{
			Safety.AssertEqual("unexpected value", "expected value", "message");
		}

		/// <summary>
		/// Ensures <see cref="Safety.AssertEqual"/> does not throw an exception when called with
		/// a <see langword="null"/> value and expected value.
		/// </summary>
		[TestMethod]
		public void TestAssertEqualWithNullValueAndNullExpectedValue()
		{
			Safety.AssertEqual(null, null, "message");
		}

		/// <summary>
		/// Ensures <see cref="Safety.AssertEqual"/> correctly throws <see cref="AssertionFailedException"/>
		/// when called with a <see langword="null"/> value and a non-<see langword="null"/> 
		/// expected value.
		/// </summary>
		[TestMethod]
		[ExpectedException(typeof(AssertionFailedException))]
		public void TestAssertEqualWithNullValueAndNonNullExpectedValue()
		{
			Safety.AssertEqual(null, "expected value", "message");
		}

		/// <summary>
		/// Ensures <see cref="Safety.AssertEqual"/> correctly throws <see cref="AssertionFailedException"/>
		/// when called with a non-<see langword="null"/> value and a <see langword="null"/> 
		/// expected value.
		/// </summary>
		[TestMethod]
		[ExpectedException(typeof(AssertionFailedException))]
		public void TestAssertEqualWithNonNullValueAndNullExpectedValue()
		{
			Safety.AssertEqual("value", null, "message");
		}

		/// <summary>
		/// Ensures <see cref="Safety.AssertEqual"/> correctly throws <see cref="ArgumentNullException"/>
		/// when called with a <see langword="null"/> message.
		/// </summary>
		[TestMethod]
		[ExpectedException(typeof(ArgumentNullException))]
		public void TestAssertEqualWithNullMessage()
		{
			Safety.AssertEqual("value", "value", null);
		}

		#endregion // AssertEqual

		#region AssertInRange

		/// <summary>
		/// Ensures <see cref="Safety.AssertInRange"/> does not throw an exception when called with
		/// a value equal to the lower bound.
		/// </summary>
		[TestMethod]
		public void TestAssertInRangeWithValueEqualToLowerBound()
		{
			// 1 falls in 1..3 so no exception.
			Safety.AssertInRange(1, 1, 3, "message");
		}

		/// <summary>
		/// Ensures <see cref="Safety.AssertInRange"/> does not throw an exception when called with
		/// a value between the lower bound and the upper bound.
		/// </summary>
		[TestMethod]
		public void TestAssertInRangeWithValueBetweenBounds()
		{
			// 2 falls in 1..3 so no exception.
			Safety.AssertInRange(2, 1, 3, "message");
		}

		/// <summary>
		/// Ensures <see cref="Safety.AssertInRange"/> does not throw an exception when called with
		/// a value equal to the upper bound.
		/// </summary>
		[TestMethod]
		public void TestAssertInRangeWithValueEqualToUpperBound()
		{
			// 3 falls in 1..3 so no exception.
			Safety.AssertInRange(3, 1, 3, "message");
		}

		/// <summary>
		/// Ensures <see cref="Safety.AssertInRange"/> correctly throws <see cref="AssertionFailedException"/>
		/// when called with a value lower than the lower bound.
		/// </summary>
		[TestMethod]
		[ExpectedException(typeof(AssertionFailedException))]
		public void TestAssertInRangeWithValueBelowLowerBound()
		{
			// 0 falls outside 1..3 so exception.
			Safety.AssertInRange(0, 1, 3, "message");
		}

		/// <summary>
		/// Ensures <see cref="Safety.AssertInRange"/> correctly throws <see cref="AssertionFailedException"/>
		/// when called with a value higher than the upper bound.
		/// </summary>
		[TestMethod]
		[ExpectedException(typeof(AssertionFailedException))]
		public void TestAssertInRangeWithValueAboveUpperBound()
		{
			// 4 falls outside 1..3 so exception.
			Safety.AssertInRange(4, 1, 3, "message");
		}

		/// <summary>
		/// Ensures <see cref="Safety.AssertInRange"/> correctly throws <see cref="AssertionFailedException"/>
		/// when called with a <see langword="null"/> value.
		/// </summary>
		[TestMethod]
		[ExpectedException(typeof(AssertionFailedException))]
		public void TestAssertInRangeWithNullValue()
		{
			Safety.AssertInRange(null, 1, 3, "message");
		}

		/// <summary>
		/// Ensures <see cref="Safety.AssertInRange"/> correctly throws <see cref="ArgumentNullException"/>
		/// when called with a <see langword="null"/> lower bound.
		/// </summary>
		[TestMethod]
		[ExpectedException(typeof(ArgumentNullException))]
		public void TestAssertInRangeWithNullLowerBound()
		{
			Safety.AssertInRange(2, null, 3, "message");
		}

		/// <summary>
		/// Ensures <see cref="Safety.AssertInRange"/> correctly throws <see cref="ArgumentNullException"/>
		/// when called with a <see langword="null"/> upper bound.
		/// </summary>
		[TestMethod]
		[ExpectedException(typeof(ArgumentNullException))]
		public void TestAssertInRangeWithNullUpperBound()
		{
			Safety.AssertInRange(2, 1, null, "message");
		}

		/// <summary>
		/// Ensures <see cref="Safety.AssertInRange"/> correctly throws <see cref="ArgumentNullException"/>
		/// when called with a <see langword="null"/> message.
		/// </summary>
		[TestMethod]
		[ExpectedException(typeof(ArgumentNullException))]
		public void TestAssertInRangeWithNullMessage()
		{
			Safety.AssertInRange(2, 1, 3, null);
		}

		#endregion // AssertInRange

		#endregion // Methods

	}

}
